﻿using System;
using System.Diagnostics;

namespace SfsTools.Core
{
    /// <summary>
    /// Stores the allocated block regions as a tree.
    /// </summary>
    internal class BlockRegionTree : Object
    {
        #region Properties

        /// <summary>
        /// Contains the root node.
        /// </summary>
        private Node FRoot;

        #endregion

        #region Methods

        /// <summary>
        /// Adds a new block region to the region tree.
        /// </summary>
        /// <param name="region">The block region.</param>
        /// <param name="value">The value object.</param>
        /// <exception cref="ArgumentException">The block region overlaps with one or more regions already in the tree.</exception>
        public void Add(BlockRegion region, Object value)
        {
            //
        }

        #endregion

        #region Constructors
        /// <overloads>Initializes a new instance of <see cref="BlockRegionTree"/>.</overloads>
        /// <summary>
        /// Initializes a new instance of <see cref="BlockRegionTree"/>.
        /// </summary>
        /// <param name="length">The count of blocks.</param>
        [DebuggerStepThrough]
        public BlockRegionTree(Int64 length)
            : base()
        {
            FRoot = new UnsplitNode(new BlockRegion(0, length));
        }
        #endregion

        #region Helper classes

        /// <summary>
        /// Represents a node.
        /// </summary>
        private abstract class Node : Object
        {
            #region Properties

            /// <summary>
            /// Contains the parent node.
            /// </summary>
            public readonly Node Parent;
            /// <summary>
            /// Contains the region.
            /// </summary>
            public readonly BlockRegion Region;
            /// <summary>
            /// The value object.
            /// </summary>
            public Object Value;
            /// <summary>
            /// Gets a value indicating how many subregions is this region split.
            /// </summary>
            public abstract int SplitCount
            {
                get;
            }

            #endregion

            #region Constructors
            /// <overloads>Initializes a new instance of <see cref="Node"/>.</overloads>
            /// <summary>
            /// Initializes a new instance of <see cref="Node"/>.
            /// </summary>
            /// <param name="region">The block region.</param>
            [DebuggerStepThrough]
            public Node(BlockRegion region)
                : base()
            {
                Region = region;
            }
            /// <summary>
            /// Initializes a new instance of <see cref="Node"/>.
            /// </summary>
            /// <param name="region">The block region.</param>
            /// <param name="value">The value object.</param>
            [DebuggerStepThrough]
            public Node(BlockRegion region, Object value)
                : base()
            {
                Region = region;
                Value = value;
            }
            /// <summary>
            /// Initializes a new instance of <see cref="Node"/>.
            /// </summary>
            /// <param name="parent">The parent node.</param>
            /// <param name="region">The block region.</param>
            /// <exception cref="ArgumentNullException">The argument <paramref name="parent"/> is <see langword="null"/>.</exception>
            [DebuggerStepThrough]
            public Node(Node parent, BlockRegion region)
                : base()
            {
                if (parent == null)
                    throw new ArgumentNullException("parent");
                Parent = parent;
                Region = region;
            }
            /// <summary>
            /// Initializes a new instance of <see cref="Node"/>.
            /// </summary>
            /// <param name="parent">The parent node.</param>
            /// <param name="region">The block region.</param>
            /// <param name="value">The value object.</param>
            /// <exception cref="ArgumentNullException">The argument <paramref name="parent"/> is <see langword="null"/>.</exception>
            [DebuggerStepThrough]
            public Node(Node parent, BlockRegion region, Object value)
                : base()
            {
                if (parent == null)
                    throw new ArgumentNullException("parent");
                Parent = parent;
                Region = region;
                Value = value;
            }
            #endregion
        }

        /// <summary>
        /// Represents an unsplit node.
        /// </summary>
        private class UnsplitNode : Node
        {
            #region Properties
            
            /// <summary>
            /// Gets a value indicating how many subregions is this region split.
            /// </summary>
            public override int SplitCount
            {
                [DebuggerStepThrough]
                get
                {
                    return 1;
                }
            }
                
            #endregion
            
            #region Constructors
            /// <overloads>Initializes a new instance of <see cref="UnsplitNode"/>.</overloads>
            /// <summary>
            /// Initializes a new instance of <see cref="UnsplitNode"/>.
            /// </summary>
            /// <param name="region">The block region.</param>
            [DebuggerStepThrough]
            public UnsplitNode(BlockRegion region)
                : base(region)
            {
            }
            /// <summary>
            /// Initializes a new instance of <see cref="UnsplitNode"/>.
            /// </summary>
            /// <param name="region">The block region.</param>
            /// <param name="value">The value object.</param>
            [DebuggerStepThrough]
            public UnsplitNode(BlockRegion region, Object value)
                : base(region, value)
            {
            }
            /// <summary>
            /// Initializes a new instance of <see cref="UnsplitNode"/>.
            /// </summary>
            /// <param name="parent">The parent node.</param>
            /// <param name="region">The block region.</param>
            /// <exception cref="ArgumentNullException">The argument <paramref name="parent"/> is <see langword="null"/>.</exception>
            [DebuggerStepThrough]
            public UnsplitNode(Node parent, BlockRegion region)
                : base(parent, region)
            {
            }
            /// <summary>
            /// Initializes a new instance of <see cref="UnsplitNode"/>.
            /// </summary>
            /// <param name="parent">The parent node.</param>
            /// <param name="region">The block region.</param>
            /// <param name="value">The value object.</param>
            /// <exception cref="ArgumentNullException">The argument <paramref name="parent"/> is <see langword="null"/>.</exception>
            [DebuggerStepThrough]
            public UnsplitNode(Node parent, BlockRegion region, Object value)
                : base(parent, region, value)
            {
            }
            #endregion
        }

        #endregion
    }
}
